package com.mp.approvalreq.service.strategy;

import com.mp.approvalreq.entity.DuplicateStrategy;
import com.mp.approvalreq.entity.Flow;
import com.mp.approvalreq.util.FlowUtils;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Created by liuqi on 2018/11/22.
 */
public class DuplicateStrategyImpl implements DuplicateStrategy {
	private static final Logger logger = LoggerFactory.getLogger(DuplicateStrategyImpl.class);

	private Integer type;

	public DuplicateStrategyImpl(Integer type) {
		if (type == null) {
			type = DuplicateStrategy.REMAIN_LAST_ITEM;
			logger.error("去重策略为空");
		}
		this.type = type;
	}


	@Override
	public List<Flow> removeRepeat(List<Flow> flows) {
		logger.info("去重前:{}", flows);
		List<Flow> list;
		switch (type) {
			case DuplicateStrategy.REMAIN_LAST_ITEM:
				list = remainLast(flows);
				break;
			case DuplicateStrategy.REMAIN_FIRST_ITEM:
				list = remainFirst(flows);
				break;
			case DuplicateStrategy.REMOVE_FOLLOW_ITEM:
				list = removeContinuity(flows);
				break;
			case DuplicateStrategy.NO_REMOVE:
				list = flows;
				break;
			default:
				throw new RpcServerLogicalException(1, "未知的去重策略");
		}
		logger.info("去重后:{}", list);
		if (flows.size() != list.size()) {
			resetOrdering(list);
		}
		return list;
	}

	/**
	 * 重置审批层级
	 *
	 * @param list
	 */
	private void resetOrdering(List<Flow> list) {
		TreeSet<Integer> orderingSet = new TreeSet<>();
		for (Flow flow : list) {
			orderingSet.add(flow.getOrdering());
		}
		if (orderingSet.size() == orderingSet.last()) {
			logger.info("无需重置");
			return;
		}
		int ordering = 1;
		for (Flow flow : list) {
			List<Flow> currentFlows = FlowUtils.getFlowsByOrdering(list, flow.getOrdering());
			if (flow.getOrdering() != ordering) {
				flow.setOrdering(ordering);
			}
			if (flow.getType() == Flow.MODE_DEFAULT || currentFlows.size() == 1) {
				ordering++;
			}
		}
	}

	/**
	 * 连续时去重
	 *
	 * @param flows
	 * @return
	 */
	private List<Flow> removeContinuity(List<Flow> flows) {
		List<Flow> list = new ArrayList<>();
		for (int i = 0; i < flows.size(); i++) {
			Flow flow = flows.get(i);
			Flow nextFlow = i < flows.size() - 1 ? flows.get(i + 1) : null;
			if (Utils.isNotNull(nextFlow) && Objects.equals(flow.getCompanyInfoId(), nextFlow.getCompanyInfoId())) {
				continue;
			}
			list.add(flow);
		}
		return list;
	}

	/**
	 * 保留第一个元素
	 *
	 * @param flows
	 * @return
	 */
	private List<Flow> remainFirst(List<Flow> flows) {
		List<Flow> list = new ArrayList<>();
		for (int i = 0; i < flows.size(); i++) {
			Flow flow = flows.get(i);
			if (existUserFlow(flow, flows.subList(0, i))) {
				continue;
			}
			list.add(flow);
		}
		return list;
	}

	/**
	 * 保留最后一个元素
	 *
	 * @param flows
	 * @return
	 */
	private List<Flow> remainLast(List<Flow> flows) {
		List<Flow> list = new ArrayList<>();
		for (int i = 0; i < flows.size(); i++) {
			Flow flow = flows.get(i);
			if (existUserFlow(flow, flows.subList(i + 1, flows.size()))) {
				continue;
			}
			list.add(flow);
		}
		return list;
	}

	private boolean existUserFlow(Flow flow, List<Flow> flows) {
		return flows.stream().anyMatch(f -> Objects.equals(f.getCompanyInfoId(), flow.getCompanyInfoId()));
	}


}
